<template>
  <div class="hello">
    <el-container>
      <el-container>
        <el-aside class="aside">
          <el-collapse
            v-model="activeNames"
            @change="handleChange"
            class="collapse"
          >
            <el-collapse-item name="graphs-list">
              <template #title>
                <span style="min-width: 60px; text-align: left"
                  >{{ $tr("Project") }}:</span
                >
                <span class="project-title-collapse">{{ workdir }}</span>
              </template>
              <graphs-list
                ref="graphs-list"
                :current-graph="chartInfo.name"
                @new-graph="onNewGraph"
              ></graphs-list>
            </el-collapse-item>

            <el-collapse-item :title="$tr('Chart Meta')" name="chart-meta">
              <el-form size="small">
                <el-form-item label="Name" class="chart-name-show">
                  <span>
                    {{ chartInfo.name }}
                  </span>
                  <rename-graph
                    :oldName="chartInfo.name"
                    @rename="onRename"
                  ></rename-graph>
                </el-form-item>
              </el-form>
            </el-collapse-item>

            <el-collapse-item
              :title="$tr('Port Bind')"
              name="port-bind"
              :disabled="!(chartInfo.type == 'route')"
            >
              <!-- 当图的类型不是route的时候，将被禁用。 -->
              <port-bind :status-mgr="statusMgr" ref="port-binder"></port-bind>
            </el-collapse-item>
            <el-collapse-item :title="$tr('Simulation')" name="simulation">
              <!-- 当图的类型不是route的时候，将被禁用。 -->
              <simulation-configs-panel></simulation-configs-panel>
            </el-collapse-item>
            <el-collapse-item :title="$tr('Nodes List')" name="node-list">
              <div style="height: 600px; overflow: scroll">
                <nodes-table ref="nodes-table"></nodes-table>
              </div>
            </el-collapse-item>
          </el-collapse>
        </el-aside>
        <el-container>
          <!-- 工具栏 -->
          <el-header class="header">
            <el-row class="toolbar">
              <el-tooltip :content="$tr('Goto start page')">
                <el-button @click="onGotoGuide">
                  <el-icon>
                    <home-filled />
                  </el-icon>
                </el-button>
              </el-tooltip>
              <config-panel></config-panel>
              <new-project-dialog button-type="tool"></new-project-dialog>
              <open-project-dialog button-type="tool"></open-project-dialog>

              <!-- <el-tooltip content="Show Demos">
                <el-button @click="demos">Demos </el-button>
              </el-tooltip> -->
              <el-tooltip :content="$tr('Download Json')">
                <el-button @click="download">
                  <el-icon>
                    <download />
                  </el-icon>
                </el-button>
              </el-tooltip>
              <el-tooltip :content="$tr('Upload Local Json File')">
                <el-upload
                  action="https://jsonplaceholder.typicode.com/posts/"
                  :limit="1"
                  accept=".json"
                  :http-request="load"
                  list-type="text"
                  :show-file-list="false"
                  class="upload-json"
                >
                  <el-button>
                    <el-icon>
                      <upload />
                    </el-icon>
                  </el-button>
                </el-upload>
              </el-tooltip>
              <el-tooltip :content="$tr('Help')">
                <el-button @click="helpShow = true" disabled>
                  <el-icon>
                    <question-filled />
                  </el-icon>
                </el-button>
              </el-tooltip>
              <div style="margin-left: 50px"></div>
              <el-tooltip :content="$tr('Run')">
                <el-button @click="run">
                  <el-icon>
                    <video-play />
                  </el-icon>
                </el-button>
              </el-tooltip>
              <el-badge is-dot :hidden="!changed">
                <el-tooltip :content="$tr('Save')">
                  <el-button @click="save">
                    <el-icon>
                      <check />
                    </el-icon>
                  </el-button>
                </el-tooltip>
              </el-badge>
              <echarts-graph-list />

              <el-tooltip
                :content="
                  (logPanelShow ? $tr('Hide') : $tr('Open')) +
                  ' ' +
                  $tr('Log Panel')
                "
              >
                <el-button @click="logPanelShow = !logPanelShow">
                  <el-icon>
                    <document />
                  </el-icon>
                </el-button>
              </el-tooltip>
            </el-row>
          </el-header>

          <el-main class="main">
            <!-- <el-row class="main-row">
              <el-col :span="logPanelShow ? 16 : 24"> -->
            <flowchart-canvas
              ref="flowchart-canvas"
              class="flowchart-canvas"
              v-if="!refreshing"
              :style="{ height: logPanelShow ? '70%' : '100%' }"
            ></flowchart-canvas>
            <!-- </el-col> -->
            <!-- <el-col :span="logPanelShow ? 8 : 0"> -->
            <log-panel
              ref="log-panel"
              :style="{ height: logPanelShow ? '30%' : '0px' }"
              v-show="logPanelShow"
            />
            <!-- </el-col> -->
            <!-- </el-row> -->
          </el-main>
        </el-container>
      </el-container>
    </el-container>
  </div>
</template>

<script lang="ts">
import FlowchartCanvas from "./flowchart/FlowchartCanvas.vue";
import NodesTable from "./nodeslist/NodesTable.vue";
import PortBind from "./panels/PortBind.vue";
import GraphsList from "@/components/panels/GraphsList.vue";
import { defineComponent, reactive, ref } from "vue";
import { emitLoad, emitRun, setOnLoad } from "./EventBus";
import ConfigPanel from "./panels/ConfigPanel.vue";
// eslint-disable-next-line
// @ts-ignore:next-line
import SomeIcon from "@/assets/icons/sine-wave.svg";
import { StatusManager } from "./flowchart/statusmgr";
import {
  ChartMeta,
  Edge,
  FlowchartJSON,
  Info,
  Node,
  RouteSettings,
} from "./flowchart/models";
import { exportFile } from "./flowchart/io";
import {
  getChart,
  newRoute,
  renameChart,
  revalidateCardsCache,
  saveChart,
} from "@/api/cards";

import md5 from "crypto-js/md5";
import RenameGraph from "@/components/panels/RenameGraph.vue";
import NewProjectDialog from "@/components/panels/NewProjectDialog.vue";
import OpenProjectDialog from "@/components/panels/OpenProjectDialog.vue";
import store from "@/api/store";
import {
  Download,
  Check,
  VideoPlay,
  Upload,
  HomeFilled,
  QuestionFilled,
  TrendCharts,
  Document,
} from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
import EchartsGraphList from "@/components/oscilloscope/EChartsGraphList.vue";
import SimulationConfigsPanel from "./panels/SimulationConfigsPanel.vue";
import LogPanel from "./panels/LogPanel.vue";
export default defineComponent({
  components: {
    FlowchartCanvas,
    NodesTable,
    ConfigPanel,
    PortBind,
    GraphsList,
    RenameGraph,
    NewProjectDialog,
    OpenProjectDialog,
    Download,
    Check,
    VideoPlay,
    Upload,
    HomeFilled,
    QuestionFilled,
    // SvgIcon
    EchartsGraphList,
    SimulationConfigsPanel,
    LogPanel,
    Document,
  },
  name: "FlowchartEditor",
  props: {
    msg: String,
  },
  setup() {
    const configShow = ref(false);
    const helpShow = ref(false);
    const fileList = reactive([]);

    const statusMgr: StatusManager = ref({}) as any;
    const refreshing = ref(false);

    const chartMeta = ref<ChartMeta>({
      chartType: "main",
      label: "Untitled",
      fileName: "Untitled",
    });

    const chartInfo = ref<Info>({
      name: "Untitled",
      type: "main",
      settings: {},
    });
    return {
      configShow,
      helpShow,
      fileList,
      SomeIcon,
      statusMgr,
      refreshing,
      chartMeta,
      chartInfo,
      activeNames: ref(["1"]),
      changed: ref(false),
      timer: -1,
      hashValue: "",
      renameDialogVisible: ref(false),
      logPanelShow: ref(true),
    };
  },
  methods: {
    run() {
      const logPanel = this.$refs["log-panel"] as typeof LogPanel;
      logPanel.clearLog();
      emitRun();
    },
    onGotoGuide() {
      this.$router.push("guide");
    },
    async dump(): Promise<FlowchartJSON> {
      const r = this.$refs["flowchart-canvas"] as any;
      const r2 = this.$refs["port-binder"] as any;

      const { edges, nodes } = (await r.save()) as {
        edges: Edge[];
        nodes: Node[];
      };
      if (this.chartInfo.type == "route") {
        const routeSettings = r2.dump() as RouteSettings;
        this.chartInfo.settings = routeSettings;
      }
      const flowchartJson: FlowchartJSON = {
        nodes,
        edges,
        info: this.chartInfo,
      };
      return flowchartJson;
    },
    async download() {
      exportFile("save.json", JSON.stringify(await this.dump()));
    },
    async save() {
      await saveChart(this.chartInfo.name, "chart_name", await this.dump());
      await this.setUnModified();
    },
    demos() {
      console.log("demos");
    },
    load(e: any) {
      const f = e.file;
      const reader = new FileReader();
      reader.onload = () => {
        emitLoad(JSON.parse(reader.result as string));
      };
      reader.readAsText(f);
    },
    async onRename(newName: string): Promise<void> {
      await renameChart(this.chartInfo.name, newName);
      await (this.$refs["graphs-list"] as any).update();
      await revalidateCardsCache(); // 图的名字变了，因此需要重置缓存，重新刷新卡片列表。
      await (this.$refs["nodes-table"] as any).update();
      this.chartInfo.name = newName;
    },
    async hash(): Promise<string> {
      const d = await this.dump();
      const s = JSON.stringify(d);
      const hashStr = md5(s).toString().toUpperCase();
      return hashStr;
    },
    async setUnModified() {
      this.hashValue = await this.hash();
      this.changed = false;
    },
    // 新建图
    async onNewGraph(graphName: string) {
      await newRoute(graphName);
      await (this.$refs["graphs-list"] as any).update();
      await revalidateCardsCache(); // 图的名字变了，因此需要重置缓存，重新刷新卡片列表。
      await (this.$refs["nodes-table"] as any).update();
      const chart = await getChart(graphName, "chart_name");
      emitLoad(chart);
    },
  },
  mounted() {
    const fc = this.$refs["flowchart-canvas"] as any;
    const mgr = fc.statusMgr as StatusManager;
    this.statusMgr = mgr as any;

    // 此时画布已经加载完毕，可以直接计算一下哈希值，从而初始化画布。
    this.hash().then((value: string) => {
      this.hashValue = value;
    });
    // 设置定时器，每秒判断一下哈希值是否对的上。
    // 当加载流程图或者保存时，调用setUnmodified重新计算哈希值。
    this.timer = window.setInterval(async () => {
      const hash = await this.hash();
      if (this.hashValue != hash) {
        this.changed = true;
      }
    }, 1000);
    // 既然重新加载这么麻烦，不如直接把画布抹掉！
    setOnLoad(async (fcJson: FlowchartJSON) => {
      // 这一步的目的是将refreshing改变一下，并且等待页面响应。
      // 这样就会移除原有的画布，同时重新创建画布。
      this.refreshing = true;
      await this.$nextTick();
      this.refreshing = false;

      await this.$nextTick(); // 等待新画布创建完成
      // 立即切换当前流程图，避免出现保存错误现象
      this.chartInfo = fcJson.info;
      document.title = this.chartInfo.name;

      const fc = this.$refs["flowchart-canvas"] as any;
      await fc.load(fcJson);
      this.statusMgr = fc.statusMgr as StatusManager;

      // 加载接口绑定的参数。只有route的类型才需要加载。
      const binder = this.$refs["port-binder"] as any;
      if (this.chartInfo.type == "route") {
        binder.load(this.chartInfo.settings);
        binder.setEndpoints(this.statusMgr.getAllEndpoints());
      } else if (this.chartInfo.type == "main") {
        binder.clear();
      } else {
        console.error("Undefined fcJson info type!");
        throw Error;
      }

      // 等待流程图加载完成
      await this.$nextTick();
      if (!fc.loadErrorOccured) {
        //  流程图加载完成后，如果没有发生错误，则重新计算哈希值。
        await this.setUnModified();
      } else {
        //如果流程图加载有误，则不重新计算哈希值，并且提示错误
        ElMessage.error(
          `流程图 ${this.chartInfo.name} 无法完整加载，流程图文件可能存在问题。可点击保存当前版本，或联系开发者解决。`
        );
      }
      console.log(fc.loadErrorOccured);
    });
  },
  beforeUnmount() {
    window.clearInterval(this.timer);
  },
  computed: {
    workdir(): string {
      return store.state.workdir;
    },
  },
});
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}

ul {
  list-style-type: none;
  padding: 0;
}

li {
  display: inline-block;
  margin: 0 10px;
}

a {
  color: #42b983;
}

.header {
  height: 5vh;
  text-align: start;
  padding-top: 5px;
}

/* 这块有一个选择器，不知道哪里来的。需要覆盖掉。 */
.header .el-button + .el-button {
  margin-left: 0px;
}

.aside {
  height: 100vh;
  border: 0px;
}

.main {
  overflow: unset;
}
.main .main-row {
  margin: 0px;
  height: 100%;
}

.flowchart-canvas {
  background-color: var(--canvas-bg);
  overflow: scroll;
}

.upload-json {
  display: inline-flex;
}

.chart-name-show span {
  flex-grow: 1;
}

.aside .collapse {
  border-top: 0px;
}

.aside .collapse :deep(.el-collapse-item__header) {
  padding-left: 8px;
}

.project-title-collapse {
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  direction: rtl;
  text-align: left;
}

.toolbar :deep(.el-button) {
  border: 0px;
}
</style>
